﻿/*
 * 
 */ 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Collections.ObjectModel;

namespace Duplicate2
{
    public partial class frmMain : Form
    {
        private string sPath = Application.StartupPath;
        long lCurSize = 0; // Curent file size
        private Collection<string> mFiles = new Collection<string>();
        private int nFile = 0;
        private string mFolder = "";    // Main folder in the list box for comparing
        private string mFile = "";      // Current file for comparing in the folder(s) in the list and subfolders

        private bool bFound = false;
        private bool bStop = false;
        private bool bSkip = false;

        int file1byte;
        FileStream fs1;

        public frmMain()
        {
            InitializeComponent();
        }

        private void SetTipVisibility()
        {
            lblTip.Visible = (lstFolders.Items.Count == 0);
        }

        private long GetFileSize(string sFileName)
        {
            FileInfo fi = new FileInfo(sFileName);
            return fi.Length;
        }

        private void CompareFiles()
        {
            progressBar1.Value += 1;
            int nPercentage = 100 * progressBar1.Value / progressBar1.Maximum;
            lblPercent.Text = nPercentage.ToString() + "%";
            while (mFiles.Count > 1)
            {
                progressBar1.Value += 1;
                nPercentage = 100 * progressBar1.Value / progressBar1.Maximum;
                lblPercent.Text = nPercentage.ToString() + "%";
                mFile = mFiles[0];
                lblMsg1.Text = "Comparing '" + mFile + "' and";
                Application.DoEvents();
                bFound = false;
                bSkip = false;

                try
                {
                    fs1 = new FileStream(mFile, FileMode.Open, FileAccess.Read);
                }
                catch
                {
                    goto NextFor;   // Error -> Skip
                }
                for (int j = 1; j < mFiles.Count; j++)
                {
                    if (bSkip == true) goto NextFor;
                    if (bStop == true) return;
                    string sFile = mFiles[j];
                    if (chkExtension.Checked && !Path.GetExtension(mFile).Equals(Path.GetExtension(sFile)))
                        continue;
                    if (mFile.Equals(sFile)) continue;  // todo: not work well yet; test more.
                    if (CompareTwoFiles(sFile) == true)
                    {
                        System.Media.SystemSounds.Beep.Play();  // Beep
                        if (!bFound)
                        {
                            bFound = true;
                            // Add a group to listview
                            lvwDuplicate.Groups.Add(mFile, ""/* mFile*/);
                            //ListViewGroup lvwGroup = new ListViewGroup(mFile, "");
                            //lvwDuplicate.Groups.Insert(0, lvwGroup);
                            lvwDuplicate.Items.Add(new ListViewItem(mFile, lvwDuplicate.Groups[mFile]));
                        }
                        lvwDuplicate.Items.Add(new ListViewItem(sFile, lvwDuplicate.Groups[mFile]));
                        mFiles.RemoveAt(j);
                        j--;    // coz just remove 1
                        //lblRemain.Text = mFiles.Count.ToString();
                        label3.Text = "Duplicated file(s) : " + lvwDuplicate.Items.Count.ToString();
                    }
                    fs1.Seek(0, SeekOrigin.Begin);  // Move to beginning to compare with another file
                    //pgb.Value += 1;
                }
            NextFor:
                fs1.Close();
                mFiles.RemoveAt(0);
            }
        }

        // Recursive to get turn to every file
        private void RecursiveCountFile(string FolderName)
        {
            try
            {
                if (bStop == true) return;  // For Foldername with 0 files inside
                string[] sFiles = Directory.GetFiles(FolderName, "*.*");
                lblMsg2.Text = FolderName;
                Application.DoEvents();
                foreach (string sFile in sFiles)
                {
                    if (bStop == true) return;
                    lblMsg1.Text = "Collecting files: " + nFile++.ToString("N0");
                    Application.DoEvents();
                    ListViewItem lvwItem = new ListViewItem(GetFileSize(sFile).ToString());
                    lvwItem.SubItems.Add(sFile);
                    listView1.Items.Add(lvwItem);
                }
            }
            catch { }
            try
            {
                foreach (string sFolder in Directory.GetDirectories(FolderName, "*.*"))
                {
                    RecursiveCountFile(sFolder);
                }
            }
            catch { }
        }

        // Compare two files (binary); mFile and File2
        private bool CompareTwoFiles(string File2)
        {
            lblMsg2.Text = "'" + File2 + "'...";
            Application.DoEvents();
            // This method accepts two strings the represent two files to 
            // compare. A return value of 0 indicates that the contents of the files
            // are the same. A return value of any other value indicates that the 
            // files are not the same.
            //private bool FileCompare(string file1, string file2)
            //{
            //int file1byte;
            int file2byte;
            //FileStream fs1;
            FileStream fs2;

            // Open the two files.
            //fs1 = new FileStream(mFile, FileMode.Open, FileAccess.Read);
            try
            {
                fs2 = new FileStream(File2, FileMode.Open, FileAccess.Read);
            }
            catch
            {
                return false;   // If can't read (in use), just return, skip
            }
            // Check the file sizes. If they are not the same, the files 
            // are not the same.
            if (fs1.Length != fs2.Length)
            {
                // Close the file
                //fs1.Close();
                fs2.Close();

                // Return false to indicate files are different
                return false;
            }

            // Read and compare a byte from each file until either a
            // non-matching set of bytes is found or until the end of
            // file1 is reached.
            do
            {
                if (bStop) return false;
                Application.DoEvents();
                // Read one byte from each file.
                file1byte = fs1.ReadByte();
                file2byte = fs2.ReadByte();
            }
            //while ((file1byte == file2byte) && (file1byte != -1 && file2byte != -1));
            while ((file1byte == file2byte) && (file1byte != -1));

            // Close the files.
            //fs1.Close();
            fs2.Close();

            // Return the success of the comparison. "file1byte" is 
            // equal to "file2byte" at this point only if the files are 
            // the same.
            return ((file1byte - file2byte) == 0);

        }

        private void btnCompare_Click(object sender, EventArgs e)
        {
            //todo: save & shutdown when done
            // Play more than one files (try to seperate by space)
            bStop = false;
            if (btnCompare.Text == "Stop")
            {
                bStop = true;
                btnSaveResult.Enabled = true;
                btnLoadResult.Enabled = true;
                nFile = 0;
                return;
            }
            btnCompare.Text = "Stop";
            progressBar1.Value = 0;
            label3.Text = "Duplicated file(s)";
            lblPercent.Text = "";
            lvwDuplicate.Items.Clear();
            lvwDuplicate.Groups.Clear();
            mFiles.Clear();

            lstFolders.Enabled = false;
            btnAdd.Enabled = false;
            btnRemove.Enabled = false;
            btnLoadResult.Enabled = false;
            // Count files
            lblMsg1.Text = "Preparing files to compare...";
            lblMsg2.Location = new Point(62, 176);
            listView1.Items.Clear();
            Application.DoEvents();

            for (int i = 0; i < lstFolders.Items.Count; i++)
            {
                mFolder = lstFolders.Items[i].ToString();
                RecursiveCountFile(mFolder);
            }
            lblMsg2.Text = "";
            lblMsg2.Location = new Point(116, 176);
            if (bStop == true) goto End;
            //todo: return if listview count < 2 = nothing to compare
            if (listView1.Items.Count < 2) goto End;
            btnCompare.Enabled = true;
            // Sort
            lblMsg1.Text = "Sorting files...";
            Application.DoEvents();
            listView1.Sorting = SortOrder.Ascending;
            listView1.Sort();
            progressBar1.Maximum = listView1.Items.Count;
            progressBar1.Value = 0;
            progressBar1.Visible = true;
            lCurSize = long.Parse(listView1.Items[0].Text);
            for (int nInd = 0; nInd < listView1.Items.Count; nInd++)
            {
                if (bStop) goto End;
                long lSize = long.Parse(listView1.Items[nInd].Text);
                if (lCurSize != lSize)
                {
                    CompareFiles(); // Compare a group of files with the same size
                    mFiles.Clear();
                    lCurSize = lSize;
                    //lblMsg1.Text = "Adding a group files to compare list...";
                    //Application.DoEvents();
                }
                string sFile = listView1.Items[nInd].SubItems[1].Text;
                mFiles.Add(sFile);
                //progressBar1.Value += 1;
                
            }
            // Last groups
            if (mFiles.Count >= 2)
                CompareFiles();
            else
            {
                progressBar1.Value = progressBar1.Maximum;
                lblPercent.Text = "100%";
            }
        End:
            btnCompare.Text = "&Search Now";
            if (!bStop)
            {
                lblMsg1.Text = "Done.";
            }
            else
                lblMsg1.Text = "Aborted by user.";
            lblMsg2.Text = "";

            listView1.Items.Clear();
            lstFolders.Enabled = true;
            btnAdd.Enabled = true;
            btnRemove.Enabled = true;

            btnCompare.Enabled = true;
            btnLoadResult.Enabled = true;
            btnSaveResult.Enabled = true;
            //this.Text = DateTime.Now.ToString();
            Properties.Settings.Default.Continue = false;   // Done. no contiue
        }

        private void btnRemove_Click(object sender, EventArgs e)
        {
            if (lstFolders.SelectedIndex != -1)
                lstFolders.Items.RemoveAt(lstFolders.SelectedIndex);
            btnCompare.Enabled = (lstFolders.Items.Count > 0);
            SetTipVisibility();
        }

        private void btnAdd_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog fbd = new FolderBrowserDialog();
            fbd.SelectedPath = Properties.Settings.Default.InitDir; //lstFolders.Items[lstFolders.Items.Count - 1].ToString();

            if (fbd.ShowDialog() == DialogResult.OK)
            {
                lstFolders.Items.Add(fbd.SelectedPath);
                Properties.Settings.Default.InitDir = fbd.SelectedPath;
                Properties.Settings.Default.Save();
            }
            btnCompare.Enabled = (lstFolders.Items.Count > 0);
            SetTipVisibility();
        }

        private void frmMain_Load(object sender, EventArgs e)
        {
            lblMsg1.Text = "Ready.";
            lblMsg2.Text = "";
            lblPercent.Text = "";
            if (Properties.Settings.Default.Continue == true)
            {
                string sMsg = "You did not finish comparing your files yet.\nDo you want to continue checking them?";
                if (MessageBox.Show(sMsg, "Loading", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                    btnLoad_Click(sender, e);
            }
        }

        private void btnDelete_Click(object sender, EventArgs e)
        {
            int nCount = lvwDuplicate.SelectedItems.Count;
            if (nCount < 1)
                return;
            string sMsg = "";
            sMsg = "Are you sure you want to delete ";
            if (nCount == 1)
                sMsg += "this file?";
            else
                sMsg += "these " + nCount + " files?";
            if (MessageBox.Show(sMsg, "Confirm Delete", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
                return;
            this.Cursor = Cursors.WaitCursor;
            for (int i = lvwDuplicate.SelectedItems.Count - 1; i >= 0; i--)
            {
                string sFile = lvwDuplicate.SelectedItems[i].Text;
                try
                {
                    //System.IO.File.Delete(sFile);
                    Recycle.DeleteFilesToRecycleBin(sFile); // Send to recycle bin                   
                    lvwDuplicate.SelectedItems[i].Remove();
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error while deleting file.\n" + ex.Message, "Delete", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    this.Cursor = Cursors.Default;
                }
            }
            // Clear groups if item remain 1
            for (int i = lvwDuplicate.Groups.Count - 2; i >= 0; i--)
            {
                if (lvwDuplicate.Groups[i].Items.Count < 2)
                {
                    //lvwDuplicate.Groups[i].Items.Clear();
                    for (int j = 0; j <= lvwDuplicate.Groups[i].Items.Count - 1; j++)
                    {
                        //MessageBox.Show(lvwDuplicate.Groups[i].Items[j].Text);
                        lvwDuplicate.Groups[i].Items[j].Remove();
                    }

                    lvwDuplicate.Groups.RemoveAt(i);
                }
            }
            label3.Text = "Duplicated file(s) : " + lvwDuplicate.Items.Count.ToString();
            this.Cursor = Cursors.Default;
        }

        private void lvwDuplicate_DoubleClick(object sender, EventArgs e)
        {
            btnPlay_Click(sender, e);
        }

        private void btnPlay_Click(object sender, EventArgs e)
        {
            if (lvwDuplicate.SelectedItems.Count < 1)
                return;
            string sFile = lvwDuplicate.SelectedItems[0].Text;
            /*for (int i = 0; i < lvwDuplicate.SelectedItems.Count; i++)
            {
                sFile += @"""" + lvwDuplicate.SelectedItems[0].Text + @"""" + ", ";
            }*/
            //wmp.openPlayer(sFile);
            //sFile = sFile.Remove(sFile.Length - 2);
            if (!File.Exists(sFile))
            {
                MessageBox.Show("The file you want to play does not exist.", "Play", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }
            try
            {
                System.Diagnostics.Process.Start(sFile);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void btnLocate_Click(object sender, EventArgs e)
        {
            if (lvwDuplicate.SelectedItems.Count < 1)
                return;
            string sFile = lvwDuplicate.SelectedItems[0].Text;
            string sCommandLine = "/select, " + sFile;
            System.Diagnostics.Process.Start("explorer", sCommandLine);
        }

        private void llbSkip_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            bSkip = true;
        }

        private void btnSave_Click(object sender, EventArgs e)
        {

            // Save folders in list (to compare)
            string sFile = Path.Combine(sPath, "Folder.ept");
            using (StreamWriter sw = new StreamWriter(sFile))
            {
                for (int i = 0; i < lstFolders.Items.Count; i++)
                {
                    sw.WriteLine(lstFolders.Items[i]);
                }
                sw.Close();
            }

            // Save result, seperated by ';'
            sFile = Path.Combine(sPath, "Result.ept");
            using (StreamWriter sw = new StreamWriter(sFile))
            {
                for (int i = 0; i < lvwDuplicate.Groups.Count; i++)
                {
                    for (int j = 0; j < lvwDuplicate.Groups[i].Items.Count; j++)
                    {
                        sw.WriteLine(lvwDuplicate.Groups[i].Items[j].Text);
                    }
                    if (i < lvwDuplicate.Groups.Count - 1)
                        sw.WriteLine(";");
                }
                sw.Close();
            }

            // Save collection to file
            sFile = Path.Combine(sPath, "Collection.ept");
            using (StreamWriter sw = new StreamWriter(sFile))
            {
                for (int i = 0; i < mFiles.Count; i++)
                {
                    sw.WriteLine(mFiles[i]);
                }
                sw.Close();
            }
            Properties.Settings.Default.Continue = true;    // set to true for asking to continue when loading
        }

        private void btnLoad_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;
            lblMsg1.Text = "Loading settings...";
            Application.DoEvents();
            lstFolders.Items.Clear();
            mFiles.Clear();
            bStop = false;

            //todo: set msg

            // Read folers to compare
            lblMsg1.Text = "Loading folders...";
            Application.DoEvents();
            string sFile = Path.Combine(sPath, "Folder.ept");
            using (StreamReader sr = new StreamReader(sFile))
            {
                String line;
                // Read and display lines from the file until the end of 
                // the file is reached.
                while ((line = sr.ReadLine()) != null)
                {
                    lstFolders.Items.Add(line);
                }
                sr.Close();
            }

            // Read result
            lblMsg1.Text = "Loading result...";
            Application.DoEvents();
            sFile = Path.Combine(sPath, "Result.ept");
            using (StreamReader sr = new StreamReader(sFile))
            {
                String sResult;
                sResult = sr.ReadToEnd();
                sr.Close();
                string[] sResults = sResult.Split(new char[] { ';' });
                foreach (string sLine in sResults)
                {
                    string[] sLines = sLine.Split(new char[] { '\n' });    // spepeated by \n
                    for (int i = 0; i < sLines.Length; i++)
                    {
                        sLines[i] = sLines[i].Trim();
                    }
                    int k = 0;
                    if (sLines[0].Length == 0) k = 1;
                    try
                    {
                        lvwDuplicate.Groups.Add(sLines[k].Trim(), " "/* mFile*/);
                        lvwDuplicate.Items.Add(new ListViewItem(sLines[k], lvwDuplicate.Groups[sLines[k].Trim()]));
                    }
                    catch { }
                    for (int j = k + 1; j < sLines.Length; j++)
                    {
                        //if (sLines .Length > 0)

                        if (sLines[j].Trim().Length > 0)
                            lvwDuplicate.Items.Add(new ListViewItem(sLines[j].Trim(), lvwDuplicate.Groups[sLines[k].Trim()]));
                    }
                }
            }

            // Read to collection
            lblMsg1.Text = "Loading files to compare...";
            Application.DoEvents();
            sFile = Path.Combine(sPath, "Collection.ept");
            using (StreamReader sr = new StreamReader(sFile))
            {
                String line;
                // Read and display lines from the file until the end of 
                // the file is reached.
                while ((line = sr.ReadLine()) != null)
                {
                    mFiles.Add(line);
                }
                sr.Close();
            }

            btnCompare.Text = "Stop";

            lstFolders.Enabled = false;
            btnAdd.Enabled = false;
            btnRemove.Enabled = false;
            this.Cursor = Cursors.Default;

            // Start comparing
            CompareFiles();
            btnCompare.Text = "&Search Now";
            lblMsg1.Text = "Done.";
            lblMsg2.Text = "";

            lstFolders.Enabled = true;
            btnAdd.Enabled = true;
            btnRemove.Enabled = true;

            btnCompare.Enabled = true;
        }

        private void btnSaveResult_Click(object sender, EventArgs e)
        {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Filter = "ePrasart File (*.ept) | *.ept|All Files (*.*) | *.*";
            sfd.OverwritePrompt = true;
            sfd.CheckPathExists = true;

            string sFile = "";
            if (sfd.ShowDialog() == DialogResult.OK)
            {
                sFile = sfd.FileName;
                // Save result, seperated by ';'
                //sFile = Path.Combine(sPath, "Result1.kk");
                using (StreamWriter sw = new StreamWriter(sFile))
                {
                    for (int i = 0; i < lvwDuplicate.Groups.Count; i++)
                    {
                        for (int j = 0; j < lvwDuplicate.Groups[i].Items.Count; j++)
                        {
                            sw.WriteLine(lvwDuplicate.Groups[i].Items[j].Text);
                        }
                        if (i < lvwDuplicate.Groups.Count - 1)
                            sw.WriteLine(";");
                    }
                    sw.Close();
                }
            }
        }

        private void btnLoadResult_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "ePrasart File (*.ept) | *.ept|All Files (*.*) | *.*";
            ofd.CheckPathExists = true;
            ofd.CheckFileExists = true;
            if (ofd.ShowDialog() != DialogResult.OK)
                return;
            this.Cursor = Cursors.WaitCursor;
            lvwDuplicate.Groups.Clear();
            lvwDuplicate.Items.Clear();

            string sFile = ofd.FileName;
            // Read result
            //sFile = Path.Combine(sPath, "Result.kk");
            using (StreamReader sr = new StreamReader(sFile))
            {
                String sResult;
                sResult = sr.ReadToEnd();
                sr.Close();
                string[] sResults = sResult.Split(new char[] { ';' });
                foreach (string sLine in sResults)
                {
                    string[] sLines = sLine.Split(new char[] { '\n' });    // spepeated by \n
                    for (int i = 0; i < sLines.Length; i++)
                    {
                        sLines[i] = sLines[i].Trim();
                    }

                    int k = 0;
                    if (sLines[0].Length == 0) k = 1;
                    lvwDuplicate.Groups.Add(sLines[k].Trim(), " "/* mFile*/);
                    lvwDuplicate.Items.Add(new ListViewItem(sLines[k], lvwDuplicate.Groups[sLines[k].Trim()]));
                    for (int j = k + 1; j < sLines.Length; j++)
                    {
                        //if (sLines .Length > 0)

                        if (sLines[j].Trim().Length > 0)
                            lvwDuplicate.Items.Add(new ListViewItem(sLines[j].Trim(), lvwDuplicate.Groups[sLines[k].Trim()]));
                    }
                }
            }
            this.Cursor = Cursors.Default;
        }

        private void lvwDuplicate_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Delete:
                    btnDelete_Click(sender, e);
                    break;
                case Keys.Enter:
                    btnPlay_Click(sender, e);
                    break;
            }
        }

        private void btnHide_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;
            for (int i = lvwDuplicate.SelectedItems.Count - 1; i >= 0; i--)
            {
                lvwDuplicate.SelectedItems[i].Remove();
            }
            for (int i = lvwDuplicate.Groups.Count - 1; i >= 0; i--)
            {
                if (lvwDuplicate.Groups[i].Items.Count == 0)
                    lvwDuplicate.Groups.RemoveAt(i);
            }
            label3.Text = "Duplicated file(s) : " + lvwDuplicate.Items.Count.ToString();
            this.Cursor = Cursors.Default;
        }

        private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (btnCompare.Text == "&Search Now") return;
            string sMsg = "Do you want to save before closing?";
            switch (MessageBox.Show(sMsg, "Close", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question))
            {
                case DialogResult.Yes:
                    btnCompare_Click(sender, e);
                    btnSave_Click(sender, e);
                    break;
                case DialogResult.Cancel:
                    e.Cancel = true;
                    break;
            }
        }

        private void frmMain_FormClosed(object sender, FormClosedEventArgs e)
        {
            Properties.Settings.Default.Save();
            Application.Exit();
        }

        private void lstFolders_SelectedIndexChanged(object sender, EventArgs e)
        {
            btnRemove.Enabled = (lstFolders.SelectedIndex >= 0);
        }

        private void lblTip_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            btnAdd_Click(sender, e);
        }

        private void mnuFileExit_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void mnuFile_Click(object sender, EventArgs e)
        {
            mnuFileExit.Enabled = (btnCompare.Text != "Stop");
        }

        private void mnuHelpAbout_Click(object sender, EventArgs e)
        {
            frmAbout fAbout = new frmAbout();
            fAbout.ShowDialog();
        }
    }
}